<template>
  <view v-if="visible" class="popup" :class="placement" @click="click">
    <transition v-if="mask" :show="showTrans" :mode="['fade']" @click="click">
      <view class="mask" :class="props.blur ? 'blur' : ''" />
    </transition>
    <transition :show="showTrans" :mode="mode" @change="change">
      <view class="container" @click="clear">
        <slot />
      </view>
    </transition>
  </view>
</template>

<script lang="ts" setup>
import Transition, { type Mode } from '@/components/transition/transition.vue';
import type { PropType } from 'vue';
import { computed, ref, watch } from 'vue';
import { useNextTick } from '@/hooks';

const nextTick = useNextTick();

const props = defineProps({
  show: Boolean,
  mask: {
    type: Boolean,
    default: true,
  },
  blur: {
    type: Boolean,
    default: true,
  },
  placement: {
    type: String as PropType<'top' | 'right' | 'bottom' | 'left' | 'center' | 'none'>,
    default: 'center',
  },
});

const emit = defineEmits(['maskClick']);

const visible = ref(false);
const showTrans = ref(false);
const clearPropagation = ref(false);

const mode = computed<Mode>(() => {
  switch (props.placement) {
    case 'top':
      return ['slide-top'];
    case 'right':
      return ['slide-right'];
    case 'bottom':
      return ['slide-bottom'];
    case 'left':
      return ['slide-left'];
    case 'center':
      return ['zoom-in', 'fade'];
    case 'none':
      return ['none']
  }
});

function clear(e: any) {
  e.stopPropagation();
  clearPropagation.value = true;
}

function click() {
  if (clearPropagation.value) {
    return clearPropagation.value = false;
  }

  if (props.mask) {
    emit('maskClick');
  }
}

async function open() {
  visible.value = true;
  await nextTick();
  showTrans.value = true;
}

function close() {
  showTrans.value = false;
}

function change(active: boolean) {
  visible.value = active;
}

watch(() => props.show, (show) => show ? open() : close(), { flush: 'post', immediate: true });

defineExpose({ open, close });
</script>

<style lang="scss" scoped>
.popup {
  position: fixed;
  z-index: 10;

  &.top {
    top: 0;
  }

  &.right {
    right: 0;
  }

  &.left {
    left: 0;
  }

  &.bottom {
    bottom: 0;
  }

  &.center {
    .content {
      display: flex;
      flex-direction: column;
      position: fixed;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      justify-content: center;
      align-items: center;
    }
  }
}

.mask {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: rgba(0, 0, 0, .65);
}

.blur {
  backdrop-filter: blur(30rpx);
}

.content {
  position: fixed;
  left: 0;
  right: 0;
}

.container {
  display: block;
  position: relative;
}
</style>